package net.xo68.destiny.starter.worker.logger;

import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import net.xo68.destiny.contract.common.SystemConstants;
import net.xo68.destiny.core.util.TimeUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日志格式
 * @author wuxie
 * @version 2020-10-30
 */
@Slf4j
public class JobLoggerFormatter {

    //"\\{([^{}]*)(:'[\\w]+')?\\}"
    public final static String PATTERN="\\{([^{}:']*)(:'.*')?\\}";
    public final static String TIME_PATTERN="([^']*)\'([^']*)\'([^']*)";

    private final static String tag_time="time";
    private final static String tag_thread="thread";
    private final static String tag_class="class";
    private final static String tag_line="line";
    private final static String tag_massage="massage";

    private final String format;
    private final Map<String,LoggerTag> tagMap= new HashMap<>();


    public JobLoggerFormatter(String format) {
        assert StringUtils.isNotEmpty(format) : "format is null";
        this.format = format;
        parse();
    }

    /**
     * 格式化日志事件
     * @param jobLoggingEvent
     * @return
     */
    public String format(JobLoggingEvent jobLoggingEvent){
        String result=new String(this.format);
        if(jobLoggingEvent.isDecorate() && this.tagMap.containsKey(tag_time)){
            result=result.replace(this.tagMap.get(tag_time).getContent(),TimeUtils.nowString(this.tagMap.get(tag_time).getFormat()));
        }else if(!jobLoggingEvent.isDecorate()){
            result=result.replace(this.tagMap.get(tag_time).getContent(),SystemConstants.STRING_EMPTY);
        }
        if(this.tagMap.containsKey(tag_thread) && StringUtils.isNotEmpty(jobLoggingEvent.getThreadName())){
            result=result.replace(this.tagMap.get(tag_thread).getContent(),jobLoggingEvent.getThreadName());
        }else if(this.tagMap.containsKey(tag_thread)){
            result=result.replace(this.tagMap.get(tag_thread).getContent(),SystemConstants.STRING_EMPTY);
        }
        if(this.tagMap.containsKey(tag_class) && StringUtils.isNotEmpty(jobLoggingEvent.getClassName())){
            result=result.replace(this.tagMap.get(tag_class).getContent(),jobLoggingEvent.getClassName());
        }else if(this.tagMap.containsKey(tag_class)) {
            result=result.replace(this.tagMap.get(tag_class).getContent(),SystemConstants.STRING_EMPTY);
        }
        if(this.tagMap.containsKey(tag_line)){
            result=result.replace(this.tagMap.get(tag_line).getContent(), String.valueOf(jobLoggingEvent.getLineName()));
        }
        if(this.tagMap.containsKey(tag_massage) && StringUtils.isNotEmpty(jobLoggingEvent.getMessage())){
            result=result.replace(this.tagMap.get(tag_massage).getContent(),jobLoggingEvent.getMessage());
        }else if(this.tagMap.containsKey(tag_massage)) {
            result=result.replace(this.tagMap.get(tag_massage).getContent(),SystemConstants.STRING_EMPTY);
        }
        //result=result.trim();
        return result;
    }

    private void parse(){
        Pattern pattern = Pattern.compile(PATTERN);
        Matcher matcher = pattern.matcher(this.format);

        Pattern timePattern=Pattern.compile(TIME_PATTERN);
        while (matcher.find()){
            if(matcher.groupCount()>=2 && StringUtils.isNotEmpty(matcher.group(1))){
                LoggerTag tag=new LoggerTag();
                tag.setContent(matcher.group(0));
                tag.setName(matcher.group(1));
                if(tag_time.equals(tag.getName())){
                    //log.info("{}",matcher.group());
                    Matcher timematcher = timePattern.matcher(tag.getContent());
                    if (timematcher.find()){
//                        log.info("-- {}",timematcher.group());
//                        for(int j=0;j<timematcher.groupCount();j++){
//                            log.info("time {} {}",j,timematcher.group(j));
//                        }
                        if(timematcher.groupCount()>2){
                            tag.setFormat(timematcher.group(2));
                        }

                    }
                    if(StringUtils.isEmpty(tag.getFormat())){
                        tag.setFormat(TimeUtils.DATETIME_FORMAT_LOCAL_DATE_TIME);
                    }
                }

                this.tagMap.put(tag.getName(),tag);
            }
        }
        //log.info("{}",this.tagMap);
    }

    @ToString
    @Data
    public static class LoggerTag{
        private String name;
        private String content;
        private String format;
    }

    public static void main(String[] args) {
        JobLoggerFormatter formatter=new JobLoggerFormatter("{time:'yyyy-MM-dd HH:mm:ss'} {massage}\n");

        for (int i=0;i<10;i++){
            JobLoggingEvent jobLoggingEvent=new JobLoggingEvent();
            jobLoggingEvent.setLoggerIndex(i);
            jobLoggingEvent.setDecorate(true);
            jobLoggingEvent.setMessage("msg-"+String.valueOf(i));
            jobLoggingEvent.setTimeStamp(System.currentTimeMillis());

            StackTraceElement callInfo = new Throwable().getStackTrace()[0];
            jobLoggingEvent.setClassName(callInfo.getFileName().replace(".java", "") );
            jobLoggingEvent.setMethodName(callInfo.getMethodName());
            jobLoggingEvent.setLineName(callInfo.getLineNumber());
            jobLoggingEvent.setThreadName(Thread.currentThread().getName());
            //log.info("{}",formatter.format(jobLoggingEvent));
            System.out.println(formatter.format(jobLoggingEvent));
        }
    }
}
